using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using HQLAddin.Util;
using HqlIntellisense;
using Microsoft.VisualStudio.Language.Intellisense;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Operations;
using Microsoft.VisualStudio.Utilities;
using HQLAddin.Highlighting;

namespace HQLAddin.Intellisense
{

	//[Order(Before = "default")]
	[Export(typeof (ICompletionSourceProvider))]
	[Name("HqlIntellisenseCompletionSource")]
	[ContentType("text")]
	internal class CompletionSourceProvider : ICompletionSourceProvider
	{
		[Import]
		internal IConfigurationDataProvider ConfigurationDataProvider { get; set; }

		[Import]
		internal ITextStructureNavigatorSelectorService NavigationService { get; set; }

		[Import]
		internal IGlyphService GlyphService { get; set; }

		#region ICompletionSourceProvider Members

		public ICompletionSource TryCreateCompletionSource(ITextBuffer textBuffer)
		{
			return
				textBuffer.Properties.GetOrCreateSingletonProperty(
					() => new CompletionSource(textBuffer, new HQLCodeAssist(ConfigurationDataProvider), NavigationService, GlyphService));
		}

		#endregion
	}

	internal class CompletionSource : ICompletionSource
	{
		private bool isDisposed;
		private readonly ITextBuffer textBuffer;
		private readonly IHQLCodeAssist codeAssist;
		private readonly ITextStructureNavigatorSelectorService navigationService;
		private readonly IGlyphService glyphService;

		public CompletionSource(ITextBuffer textBuffer, IHQLCodeAssist codeAssist, ITextStructureNavigatorSelectorService navigationService, IGlyphService glyphService)
		{
			this.textBuffer = textBuffer;
			this.codeAssist = codeAssist;
			this.navigationService = navigationService;
			this.glyphService = glyphService;
		}

		#region ICompletionSource Members

		public void AugmentCompletionSession(ICompletionSession session, IList<CompletionSet> completionSets)
		{
			var point = session.GetTriggerPoint(textBuffer).GetPoint(textBuffer.CurrentSnapshot);
			if (!point.IsInQueryTag()) return;
			var line = point.GetContainingLine();
			var query = textBuffer.CurrentSnapshot.GetQueryInfoAtLine(line.LineNumber);

			if(query == null) return;

			var dic = SnapshotExtensions.BuildQueryLinesToFileLines(query.QueryTagLineNumber, 
														query.Query.SplitInLines(),
														textBuffer.CurrentSnapshot.Lines.ToArray());

			var applicableTo = FindTokenSpanAtPosition(session);
			var requestor = new HqlCompletionRequestor(applicableTo, glyphService);
			var position = point.Position - dic[0].Line.Start.Position;
			if (string.IsNullOrEmpty(query.Query)) return;

			codeAssist.CodeComplete(query.Query, position, requestor);
			
			//completionSets.Clear();
			completionSets.Insert(0, requestor.CompletionSet);
		}


		private ITrackingSpan FindTokenSpanAtPosition(IIntellisenseSession session)
		{
			//return null;
			if (session.TextView == null) return null;

			var notChars = new[] {'.', ' '};
			var startOfWord = notChars.Contains((session.TextView.Caret.Position.BufferPosition - 1).GetChar());
			
			var currentPoint = (session.TextView.Caret.Position.BufferPosition) - (startOfWord ? 0 : 1);
			var navigator = navigationService.GetTextStructureNavigator(textBuffer);
			var extent = navigator.GetExtentOfWord(currentPoint);
			var text = extent.Span.GetText();

			if (!string.IsNullOrEmpty(text.Trim().Replace(Environment.NewLine, "").Replace("\n", string.Empty)))
			{
				return currentPoint.Snapshot.CreateTrackingSpan(extent.Span, SpanTrackingMode.EdgeInclusive);
			}

			return currentPoint.Snapshot.CreateTrackingSpan(
				currentPoint.Position,
				0,
				SpanTrackingMode.EdgeInclusive);
		}

		public void Dispose()
		{
			
			if (isDisposed) return;
			GC.SuppressFinalize(this);
			isDisposed = true;
		}

		#endregion
	}
}